/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Connection module header for TCP links.
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _CONNECTIONTCP_H_
#define _CONNECTIONTCP_H_

#include "connection.h"
#include <netinet/in.h>
#include <sys/poll.h> 
#include <poll.h>


#define CONNECTIONTCP_OK             CONNECTION_OK
#define CONNECTIONTCP_ERROR          CONNECTION_ERROR


/** TCP Status types.
 */
typedef enum { 
  tcpStatusConnected,       ///< Link is up.
  tcpStatusDisconnected,    ///< Link is down.
  tcpStatusError            ///< Some error exists.
} EConnectionTCPStatus;


/** TCP module instance types.
 */
typedef enum { 
  tcpStyleClient,           ///< Act in client mode. Calling Connect will attempt to connect().
  tcpStyleServer,           ///< Act in server mode. Calling Connect will attempt to accept().
  tcpStyleListeningSocket,  ///< Act as listening socket only. Calling connect \todo Does what?
  tcpStyleAsyncClient       ///< Connect as Asynchronous client, leaving the connect() call on background.
} EConnectionTCPStyle;


/** Blocking operation type.
 */
typedef enum { 
  tcpBlockingTypeBlocking,       ///< Select blocking operation.
  tcpBlockingTypeNonBlocking     ///< Select non-blocking operation.
} EConnectionTCPBlockingType;


/** Container for connection specific data.
 */
typedef struct _connectiontcp {
  EConnectionTCPStatus connectionStatus;   ///< Status: Connected/DisConnected/Error?
  EConnectionTCPStyle connectionStyle;     ///< Style; Client / Server?
  EConnectionTCPBlockingType blockingType; ///< Block; Blocking / non-blocking?
  TConnectionPtr connectionPtr;            ///< Function pointer group.
  
  int socket_fd;                           ///< shared Socket handle, used for accept():in connections, and when listening.
  int data_fd;                             ///< Client handle (this is where the data will be read/written)
  
  int port;                                ///< Port to use (Client/Server/ListenSocket)
  char *host;                              ///< Host to use (Client), stored in 'address' also.
  struct in_addr inet_addr;                ///< Address to use (Client/Server/ListenSocket)
  struct sockaddr_in socket_addr;          ///< Stores full bind() information (includes port and address)
  struct pollfd socket_status;             ///< To check if connection is Ok 
} TConnectionTCP;



/** Construct a function pointer group for use by TConnection module.
 *
 * @param con        Pointer to connection parameters
 * @return           Pointer to function pointer group typed TConnectionPtr.
 */
const TConnectionPtr *connectionTCPGetConnectionPtrEntry(const TConnectionTCP *con);

const char * connectionTCPGetPeerIP(const TConnectionTCP *con);

int connectionTCPGetPeerPort(const TConnectionTCP *con);

/**
 *
 *
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPGetHandle(TConnectionTCP *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPCreateListeningSocket(int port, struct sockaddr_in *socket_addr);

/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPSetSocketHandle(TConnectionTCP *con, int socket_fd, 
				 const struct sockaddr_in *socket_addr);

/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPSetConnectionType(TConnectionTCP *con, 
				   EConnectionTCPStyle style, 
				   EConnectionTCPBlockingType blocking);

/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPConnect(TConnectionTCP *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPDisconnect(TConnectionTCP *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPSetHost(TConnectionTCP *con, const char *hostname);


/** Set target by IP.
 *
 */
int connectionTCPSetIP(TConnectionTCP *con, const char *ipaddr);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPSetPort(TConnectionTCP *con, int port);



/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPInit(TConnectionTCP *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionTCPDeinit(TConnectionTCP *con);


/**
 * Sends formatted data. Works just like printf()-family, except
 * that the function requires a pointer to Connection.
 * @param con        Pointer to connection parameters
 * @param format     Format parameter
 * @param ...        Arguments
 * @return           Real number of bytes sent, or negative on error.
 */
int connectionTCPSendDataFormatted(TConnectionTCP *con, const char *format, ...);


/**
 * Function that sends raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to send
 * @param bufLen     Number of bytes to send
 * @return           Real number of bytes sent, or negative on error.
 */
int connectionTCPSendData(TConnectionTCP *con, const unsigned char *buffer, int bufLen);


/**
 * Function that sends raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 *
 * The 'Ex' in this function means that it's cabable for multibuffer
 * sends. (Reading from separate buffers on a single syscall())
 
 * @param con        Pointer to connection parameters
 * @param bufferA     Pointer to data buffer A to send
 * @param bufLenA     Number of bytes to send from BufferA
 * @param bufferB     Pointer to data buffer B to send
 * @param bufLenB     Number of bytes to send from BufferB
 * @return           Real TOTAL number of bytes sent, or negative on error.
 */
int connectionTCPSendDataEx(TConnectionTCP *con, 
			 const unsigned char *bufferA, 
			 int bufLenA,
			 const unsigned char *bufferB, 
			 int bufLenB);

/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     MAXIMUM number of bytes to receive
 * @return           Real number of bytes received, or negative on error.
 */
int connectionTCPReceiveData(TConnectionTCP *con, unsigned char *buffer, int bufLen); 


/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     MAXIMUM number of bytes to receive
 * @param timeout_ms Number of milliseconds to wait for new data. Negative
 *                   value means "forever", and zero is ofcourse "now".
 * @return           Real number of bytes received, or negative on error.
 *                   (The zero value means = no new bytes == timeout)
 */
int connectionTCPReceiveDataTimed(TConnectionTCP *con, 
			       unsigned char *buffer, 
			       int bufLen,
			       int timeout_ms);


/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * This function differs from the previous one so, that it waits for
 * the full buffer to fill up.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     Number of bytes to receive
 * @param timeout    Time in milliseconds to wait until the call is considered
 *                   to have timed out. Zero value for infinite wait.
 * @return           Negative value on error, otherwise number of bytes really
 *                   received. NOTE; If the command times out, number of
 *                   read bytes < readBytes.
 */
int connectionTCPReceiveDataBlock(TConnectionTCP *con, unsigned char *buffer, int readBytes, int timeout);


/**
 * Function that receives ONE LINE of text, using char 'endChar' as terminating
 * character. Line is returned as endChar stripped.
 * @param con        Pointer to connection parameters
 * @param buffer     Buffer to store data to.
 * @param bufLen     Maximum length of the buffer
 * @param endChar    Character to use for determining EOL. Default is '\n'
 * @return           Number of bytes in line or negative on error.
 */
int connectionTCPReceiveDataTextLine(TConnectionTCP *con, char *buffer, int bufLen, char endChar);

#endif //_CONNECTIONTCP_H_
